/*
 * Copyright (c) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef OHOS_VIDEO_ENCODER
#define OHOS_VIDEO_ENCODER

#include <cstdint>
#include <memory>
#include <chrono>

#include <multimedia/player_framework/native_avcodec_videoencoder.h>
#include <multimedia/player_framework/native_avcapability.h>
#include <multimedia/player_framework/native_avcodec_base.h>
#include <multimedia/player_framework/native_avformat.h>
#include <multimedia/player_framework/native_avbuffer.h>

#include "ohosdec_common.h"
#include "ohoscodecdata.h"
#include <native_window/external_window.h>

namespace ohos {
using namespace std::chrono_literals;

class VideoEncoder {
public:
    VideoEncoder(std::unique_ptr<CodecData> codecData, std::unique_ptr<VideoFormat> format);
    ~VideoEncoder();

    int32_t Create();
    int32_t Config();
    int32_t Start();
    int32_t Flush();
    int32_t PushInputData(uint8_t *pktData, size_t dataSize, int pts, int flag,
                          std::chrono::milliseconds waitTimes = 0ms);
    int32_t GetOutputBuffer(AvBufferInfo &info, std::chrono::milliseconds waitTimes = 0ms);
    int32_t GetInputBuffer(AvBufferInfo &info, std::chrono::milliseconds waitTimes = 0ms);
    
    int32_t FreeOutputData(uint32_t index);
    int32_t FreeInputData(int32_t index);
    void RequestIFrame();
    int32_t Stop();
    void Release();
    int32_t GetFormatInfo(FormatType type);

    /* 编码器回调 */
    class DataCallback {
    public:
        static void OnCodecError(OH_AVCodec *codec, int32_t errorCode,
                                 void *userData);
        static void OnCodecFormatChange(OH_AVCodec *codec, OH_AVFormat *format,
                                        void *userData);
        static void OnNeedInputBuffer(OH_AVCodec *codec, uint32_t index,
                                      OH_AVBuffer *buffer, void *userData);
        static void OnNewOutputBuffer(OH_AVCodec *codec, uint32_t index,
                                      OH_AVBuffer *buffer, void *userData);
    };

    enum class State : uint8_t {
        UNKNOWN,
        CONFIG,
        RUNNING,
        FLUSH,
        STOP,
        RELEASE
    };

    int SetCodecFormat();
    CodecData *GetCodecData();
    int32_t SetCallback();
    std::atomic<int32_t> errorCode_{0};
    OH_AVCodec *encoder_{nullptr};
    std::unique_ptr<VideoFormat> format_{nullptr};
    std::unique_ptr<CodecData> data_{nullptr};
    struct OH_AVFormat *avFormat_{nullptr};
    enum State state_{State::UNKNOWN};
    OHNativeWindow* window_{nullptr};
};
} // namespace ohos

#endif // OHOS_VIDEO_ENCODER
